#include "Blit.h"
#include "GL/glew.h"
#include "Geometry.h"
#include "Shader.h"
#include "Window.h"
#include "graphics/GLState.h"
#include <iostream>
using namespace Umikaze::Core;

std::unique_ptr<Shader> Blit::blitShader = nullptr;
uint32_t Blit::blitFbo = 0;

void Blit::init() {
  if (!blitShader) {
    blitShader = std::make_unique<Shader>("BlitShader.vert", "BlitShader.frag");
  }
  if (!blitFbo) {
    glGenFramebuffers(1, &blitFbo);
  }
}

void Blit::drawQuad() {
  static std::unique_ptr<Geometry> quad = std::make_unique<PlaneGeometry>(2, 2);
  auto &state = GlState::instance();

  state->disable(GL_DEPTH_TEST);
  state->disable(GL_STENCIL_TEST);
  state->enable(GL_CULL_FACE);
  state->cull(GL_BACK);
  quad->draw();
}

void Blit::blitToDefault(const std::shared_ptr<Texture> &color) {
  init();
  auto &state = GlState::instance();
  auto &window = Window::instance();
  state->bindFramebuffer(0);
  state->viewport(0, 0, window->getPixelWidth(), window->getPixelHeight());
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  blitShader->setTexture("colorMap", color);
  blitShader->bind();
  drawQuad();
}

void Blit::blitToDefault(const std::shared_ptr<Texture> &color,
                         const std::unique_ptr<Shader> &shader) {
  auto &state = GlState::instance();
  auto &window = Window::instance();
  state->bindFramebuffer(0);
  state->viewport(0, 0, window->getPixelWidth(), window->getPixelHeight());
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  shader->setTexture("colorMap", color);
  shader->bind();
  drawQuad();
}

void Blit::blitToDefault(const std::shared_ptr<Texture> &color,
                         const std::shared_ptr<Texture> &depth) {
  init();
  auto &state = GlState::instance();
  auto &window = Window::instance();
  state->bindFramebuffer(0);
  state->viewport(0, 0, window->getPixelWidth(), window->getPixelHeight());
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  blitShader->setTexture("colorMap", color);
  blitShader->setBool("blitDepth", true);
  blitShader->setTexture("depthMap", depth);
  blitShader->bind();
  drawQuad();
}
void Blit::blitToDefault(const std::shared_ptr<Texture> &color,
                         const std::shared_ptr<Texture> &depth,
                         const std::unique_ptr<Shader> &shader) {
  auto &state = GlState::instance();
  auto &window = Window::instance();
  state->bindFramebuffer(0);
  state->viewport(0, 0, window->getPixelWidth(), window->getPixelHeight());
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  shader->setTexture("colorMap", color);
  shader->setTexture("depthMap", depth);
  shader->bind();
  drawQuad();
}

void Blit::blitColor(const std::shared_ptr<Texture> &from,
                     const std::shared_ptr<RenderTexture> &target) {
  init();
  auto &state = GlState::instance();
  state->bindFramebuffer(blitFbo);
  target->bindAsColorAttachment(0);
  state->viewport(0, 0, target->_width, target->_height);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  blitShader->setTexture("colorMap", from);
  blitShader->bind();
  drawQuad();
}

void Blit::blitColor(const std::shared_ptr<Texture> &from,
                     const std::shared_ptr<RenderTexture> &target,
                     const std::unique_ptr<Shader> &shader) {
  init();
  auto &state = GlState::instance();
  state->bindFramebuffer(blitFbo);
  target->bindAsColorAttachment(0);
  state->viewport(0, 0, target->_width, target->_height);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  shader->setTexture("colorMap", from);
  shader->bind();

  drawQuad();
}

void Blit::blitDepth(const std::shared_ptr<Texture> &from,
                     const std::shared_ptr<RenderTexture> &target) {
  //   init();
  //   auto &state = GlState::instance();
  //   target->bindAsAttachment();
  //   from->bind(0);
  //   blitShader->use();
  //   blitShader->setInt("colorMap", 0);
  //   blitShader->setBool("blitDepth", false);
  //   drawQuad(0, 0, target->_width, target->_height);
}